package com.biotools.meerkat;

import com.biotools.meerkat.util.*;

public class HandEvaluator
{
    private static HandEval eval;
    
    public static final int rankHand(final Hand h) {
        return HandEvaluator.eval.rankHand(h);
    }
    
    public static final int rankHand7(final Hand h) {
        return HandEvaluator.eval.rankHand7(h);
    }
    
    public static final int rankHand6(final Hand h) {
        return HandEvaluator.eval.rankHand6(h);
    }
    
    public static final int rankHand5(final Hand h) {
        return HandEvaluator.eval.rankHand5(h);
    }
    
    public static int rankHand(final int c1, final int c2, final Hand h) {
        h.addCard(c1);
        h.addCard(c2);
        final int rank = HandEvaluator.eval.rankHand(h);
        h.removeCard();
        h.removeCard();
        return rank;
    }
    
    public static int rankHand(final Card c1, final Card c2, final Hand h) {
        h.addCard(c1);
        h.addCard(c2);
        final int rank = HandEvaluator.eval.rankHand(h);
        h.removeCard();
        h.removeCard();
        return rank;
    }
    
    public static int compareHands(final Hand h1, final Hand h2) {
        final int r1 = rankHand(h1);
        final int r2 = rankHand(h2);
        if (r1 > r2) {
            return 1;
        }
        if (r1 < r2) {
            return 2;
        }
        return 0;
    }
    
    public static int compareHands(final int rank1, final Hand h2) {
        final int r2 = rankHand(h2);
        if (rank1 > r2) {
            return 1;
        }
        if (rank1 < r2) {
            return 2;
        }
        return 0;
    }
    
    public static NChoose2IntTable getRanks(final Hand board) {
        final Hand myhand = new Hand(board);
        final NChoose2IntTable rc = new NChoose2IntTable(52);
        final Deck d = new Deck();
        d.extractHand(board);
        for (int i = d.getTopCardIndex(); i < 52; ++i) {
            myhand.addCard(d.getCard(i));
            final int n1 = d.getCard(i).getIndex();
            for (int j = i + 1; j < 52; ++j) {
                myhand.addCard(d.getCard(j));
                final int n2 = d.getCard(j).getIndex();
                rc.set(n1, n2, rankHand(myhand));
                myhand.removeCard();
            }
            myhand.removeCard();
        }
        return rc;
    }
    
    public static double handRank(final Card c1, final Card c2, final Hand h, final int np) {
        double H;
        final double HR = H = handRank(c1, c2, h);
        for (int j = 0; j < np - 1; ++j) {
            H *= HR;
        }
        return H;
    }
    
    public static double handRank(final Card c1, final Card c2, final Hand h) {
        final Hand myHand = new Hand(h);
        final Hand xxHand = new Hand(h);
        myHand.addCard(c1);
        myHand.addCard(c2);
        final int myRank = rankHand(myHand);
        final Deck d = new Deck();
        int good = 0;
        int bad = 0;
        int tied = 0;
        d.reset();
        d.extractCard(c1);
        d.extractCard(c2);
        d.extractHand(h);
        for (int i = d.getTopCardIndex(); i < 52; ++i) {
            xxHand.addCard(d.getCard(i));
            for (int j = i + 1; j < 52; ++j) {
                xxHand.addCard(d.getCard(j));
                final int v = compareHands(myRank, xxHand);
                if (v == 1) {
                    ++good;
                }
                else if (v == 2) {
                    ++bad;
                }
                else {
                    ++tied;
                }
                xxHand.removeCard();
            }
            xxHand.removeCard();
        }
        return (good + tied / 2.0) / (good + bad + tied);
    }
    
    public static double handRank(final Card c1, final Card c2, final NChoose2IntTable rankCache, final Deck dk) {
        final int c1i = c1.getIndex();
        final int c2i = c2.getIndex();
        final int myRank = rankCache.get(c1i, c2i);
        int good = 0;
        int bad = 0;
        int tied = 0;
        for (int i = dk.getTopCardIndex(); i < 52; ++i) {
            final int n1 = dk.getCard(i).getIndex();
            if (n1 != c1i && n1 != c2i) {
                for (int j = i + 1; j < 52; ++j) {
                    final int n2 = dk.getCard(j).getIndex();
                    if (n2 != c1i && n2 != c2i) {
                        final int opRank = rankCache.get(n1, n2);
                        if (myRank > opRank) {
                            ++good;
                        }
                        else if (myRank < opRank) {
                            ++bad;
                        }
                        else {
                            ++tied;
                        }
                    }
                }
            }
        }
        return (good + tied / 2.0) / (good + bad + tied);
    }
    
    public static final boolean isTheNuts(final Card c1, final Card c2, final Hand board, final NChoose2IntTable rankCache) {
        final Deck dk = new Deck();
        dk.extractCard(c1);
        dk.extractCard(c2);
        dk.extractHand(board);
        final int c1i = c1.getIndex();
        final int c2i = c2.getIndex();
        final int myRank = rankCache.get(c1i, c2i);
        for (int i = dk.getTopCardIndex(); i < 52; ++i) {
            final int n1 = dk.getCard(i).getIndex();
            if (n1 != c1i && n1 != c2i) {
                for (int j = i + 1; j < 52; ++j) {
                    final int n2 = dk.getCard(j).getIndex();
                    if (n2 != c1i && n2 != c2i && myRank < rankCache.get(n1, n2)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    
    public static HandEval getHandEval() {
        return HandEvaluator.eval;
    }
    
    public static void setHandEval(final HandEval he) {
        HandEvaluator.eval = he;
    }
}
